/**
 *  by Michael Liljenstam (ML). revisions ato.
 */

package SSF.Net;

import SSF.OS.*;
import SSF.OS.NetFlow.BytesUtil;
import SSF.Util.Streams.*;
import com.renesys.raceway.DML.*;
import com.renesys.raceway.SSF.*;
import java.text.*;

/** A prototype queue monitor built atop the SSF.Util.Streams
 * infrastructure, provided as a demonstration.
 * Monitors the IP packet arrivals and drops in a droptailQueue
 * on the NIC on which this droptailQueueMonitor is configured.
 * Writes # packet arrivals and drops to the named StreamInterface.
 *
 * <P>Uses record_type: SSF.Net.QueueRecord_2.
 *
 * @see SSF.Net.droptailQueue
 * @see SSF.Net.droptailRecordPlayer_2
 * @see SSF.Util.Streams
 */
public class droptailQueueMonitor_2 implements PacketQueueMonitor {
  private java.text.DecimalFormat fm = new DecimalFormat();
  private droptailQueue queue;
  private NIC nic;
  private long tickinterval;
  private boolean DEBUG=false;
  private boolean suppressZeros = false;
  private Host localHost;
  private double invfreq;   // inverse Net.frequency: sec/tick

  int pkts = 0;             // in current interval
  int drops = 0;            // in current interval

  ProbeSession P;
  StreamInterface S;
  int hostcode;
  int typeCode;

  /** configure the Monitor. The supported DML attributes are:
   * <PRE>
   *   monitor [
   *     use SSF.Net.droptailQueueMonitor
   *     probe_interval  %F   # recording time interval, seconds (double)
   *     suppress_zeros  %S   # suppress zero queue output, true/false
   *     debug           %S   # print verbose diagnostics, true/false
   *   ]
   * </PRE>
   */
  public void config(NIC ownerNIC, Configuration cfg) throws configException {
    nic = ownerNIC;
    queue = (droptailQueue)nic.queueManager;  // add class verification
    localHost = (Host)nic.inGraph();
    invfreq = 1.0/Net.frequency;

    // format time output
    fm.setMinimumFractionDigits(3);
    fm.setMaximumFractionDigits(3);

    // interval between record transmission, in seconds
    String str = (String)cfg.findSingle("probe_interval");
    if (str == null)
      throw new configException("\n"+nic.interfaceIdentifier()
                                +" DML attribute monitor.probeInterval must be specified");
    else
      tickinterval = Net.seconds((new Double(str)).doubleValue());

    str = (String)cfg.findSingle("debug");
    if (str != null)
      DEBUG = Boolean.valueOf(str).booleanValue();

    // suppress zero queue output option
    str = (String) cfg.findSingle("suppress_zeros");
    if (str != null)
      suppressZeros = Boolean.valueOf(str).booleanValue();
  }

  /** called by SSF.Net.NIC.init()
   */
  public void init() {
    if (DEBUG)
      System.out.println(nic.interfaceIdentifier()
	                   + " droptailQueueMonitor_2: probe interval "
                           +tickinterval+" ticks");

    try {
      P = (ProbeSession)(nic.inGraph().SessionForName("probe"));
      S = P.getRecorder();
      hostcode = P.getHostCode(nic.ID);
      typeCode = S.getRecordTypeCode("SSF.Net.QueueRecord_2");

      queue.setMonitor(this);

      SSF.OS.Timer recordTimer = new SSF.OS.Timer(nic.inGraph(), tickinterval) {
        public void callback(){
          sendRecord();
          set(tickinterval);
        }
      };

      recordTimer.set();

      //SimpleProcess sampler = new SimpleProcess(nic.inGraph()) {

      //  public void action() {
      //    sendRecord();
      //    waitFor(tickinterval);  // use ticks directly
      //  }
      //};
    } catch (ProtocolException pex) {
      System.err.println(nic.interfaceIdentifier()+ " Can't configure droptailQueueMonitor_2: "
			 + "no ProbeSession registered in host");
      System.err.println(pex.getMessage());
      System.exit(1);
    }
  }

  public void sendRecord() {
    double time = invfreq*localHost.now();

    byte[] qRecord = new byte[16];
    int startIndex = 0;

    startIndex = BytesUtil.intToBytes(queue.pktCount, qRecord, startIndex);
    startIndex = BytesUtil.intToBytes(queue.pktDropCount, qRecord, startIndex);
    startIndex = BytesUtil.intToBytes(pkts, qRecord, startIndex);
    startIndex = BytesUtil.intToBytes(drops, qRecord, startIndex);

    S.send(typeCode, hostcode, time, qRecord, 0, qRecord.length);

    if (DEBUG)
      System.out.println("QMon2: " + fm.format(time)
                          + " " + nic.interfaceIdentifier()
                          + " sumpkts " + queue.pktCount
                          + " sumdrops " + queue.pktDropCount
                          + " pkts " + pkts
                          + " drops " + drops);
				
    pkts = 0;
    drops = 0;
  }

  /**
   *  Log a packet arriving to the queue.
   */
  public void receive(ProtocolMessage msg) {
    pkts++;
    if(queue.pktDropped) drops++;
  }
}


